#include <types.h>
#include <arm.h>
#include <picirq.h>
#include <string.h>
#include <intr.h>

#define SRCPND		(uint32_t) 0x4A000000
#define INTMOD		(uint32_t) 0x4A000004
#define INTMSK		(uint32_t) 0x4A000008
#define INTPND		(uint32_t) 0x4A000010
#define INTOFFSET	(uint32_t) 0x4A000014

// Current IRQ mask
// static uint32_t irq_mask = 0xFFFFFFFF & ~(1 << INT_UART0);
static uint32_t irq_mask = 0xFFFFFFFF;
static bool did_init = 0;

static void
pic_setmask(uint32_t mask) {
    irq_mask = mask;
    if (did_init) {
        outw(INTMSK, mask);
    }
}

void
pic_enable(unsigned int irq) {
    pic_setmask(irq_mask & ~(1 << irq));
}

/* pic_init
 * initialize the interrupt, but doesn't enable them */
void
pic_init(void) {
    did_init = 1;
	
	// Very important:
	// At the boot, exceptions handlers have not been defined
	// Copy the address of exceptions handlers (defined in vectors.S) to 0x24 
	// (or Ox20 if we decide to change reset handler)
	extern char __vector_table, __vector_table_end;
    memcpy( (void*)0x24, (void*)&__vector_table,
            &__vector_table_end - &__vector_table);
	
	// Only after exceptions handlers have been defined
	// intr_enable();
	
	// Set IRQ mode for all interrupts
	outw(INTMOD, 0x0);
	
	// Mask all interrupts
	outw(INTMSK, 0xFFFFFFFF);
	
	// Might need to set priorities later
	
    if (irq_mask != (uint32_t) 0xFFFFFFFF) {
        pic_setmask(irq_mask);
    }
}

/* irq_clear
 * 	Clear a pending interrupt request
 *  necessary when handling an irq */
void
irq_clear(unsigned int source) {
	outw(SRCPND, inw(SRCPND) | 1 << source);
	// A convenient method to clear INTPND
	outw(INTPND, inw(INTPND));
}
